package org.finesys.common.security.authentication.sms;

import java.util.Map;

import org.finesys.common.constants.SecurityConstants;
import org.finesys.common.core.util.StrUtil;
import org.finesys.common.security.authentication.base.OAuth2ResourceOwnerBaseAuthenticationProvider;
import org.finesys.common.security.core.util.OAuth2ConfigurerUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class OAuth2ResourceOwnerSmsAuthenticationProvider extends OAuth2ResourceOwnerBaseAuthenticationProvider<OAuth2ResourceOwnerSmsAuthenticationToken> {

    private final StringRedisTemplate redisTemplate;

    /**
     * 构造函数
     */
    public OAuth2ResourceOwnerSmsAuthenticationProvider(HttpSecurity httpSecurity) {
        super(httpSecurity);
        this.redisTemplate = OAuth2ConfigurerUtils.getBean(httpSecurity, StringRedisTemplate.class);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        boolean supports = OAuth2ResourceOwnerSmsAuthenticationToken.class.isAssignableFrom(authentication);
        if (log.isDebugEnabled()) {
            log.debug("supports  authentication=[{}] returning {}", authentication, supports);
        }
        return supports;
    }

    @Override
    public void checkClient(RegisteredClient registeredClient) {
        assert registeredClient != null;
        if (!registeredClient.getAuthorizationGrantTypes()
                .contains(new AuthorizationGrantType(SecurityConstants.SMS))) {
            throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
        }
    }


    @Override
    public UsernamePasswordAuthenticationToken buildToken(Authentication authentication, Map<String, Object> requestParameters) {
        //获取手机号、验证码
        String mobile = (String) requestParameters.get(SecurityConstants.MOBILE);
        String captcha = (String) requestParameters.get(SecurityConstants.CAPTCHA);
        //校验手机号验证码是否正确
        additionalAuthenticationChecks(mobile, captcha);
        // 验证通过检索用户信息
        return new UsernamePasswordAuthenticationToken(mobile, captcha);
    }

    /**
     * 校验手机号验证码是否正确
     */
    protected void additionalAuthenticationChecks(String mobile, String captcha) throws AuthenticationException {
        String cacheCaptcha = redisTemplate.opsForValue().get(SecurityConstants.SMS_CODE_PREFIX + mobile);
        if (StrUtil.isBlank(cacheCaptcha) || (cacheCaptcha!=null&&!cacheCaptcha.equals(captcha))) {
            throw new BadCredentialsException(super.getMessageSourceAccessor()
                    .getMessage("OAuth2ResourceOwnerSmsAuthenticationToken.badCredentials", "Bad credentials"));
        }
        // 校验通过 删除缓存
        redisTemplate.delete(SecurityConstants.SMS_CODE_PREFIX + mobile);
    }


}
